import json
from decimal import Decimal

from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction
from django.shortcuts import render
import logging
# Create your views here.
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from goods.models import SKU
from meiduo_mall.utils.response_code import RETCODE
from meiduo_mall.utils.views import LoginRequiredJSONMixin
from orders.models import OrderInfo, OrderGoods
from users.models import Address
logger = logging.getLogger('django')

class OrderCommitView(LoginRequiredJSONMixin, View):
    def post(self,request):
        '''接受和校验参数'''
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')
        if not all([address_id,pay_method]):
            return http.HttpResponseForbidden('缺少必要参数')
        '''校验参数是否合法'''
        try:
            address = Address.objects.get(id = address_id)
        except address_id.DoesNotExist:
            return http.HttpResponseForbidden('参数address有误')
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'],OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseForbidden('参数pay_method有误')
        '''获取订单编号 年月日+user_id 2019101900000001'''
        user = request.user
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
        try:
            '''保存订单基本信息（一'''
            order = OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=address,
                total_count=0,
                total_amount=Decimal('0'),
                freight=Decimal('10.00'),
                pay_method=pay_method,
                status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else
                OrderInfo.ORDER_STATUS_ENUM['UNSEND']
            )
             # 从redis读取购物车中被勾选的商品信息
            redis_conn = get_redis_connection('carts')
            redis_cart = redis_conn.hgetall('carts_%s' % user.id)
            selected = redis_conn.smembers('selected_%s' % user.id)
            carts = {}
            for sku_id in selected:
                carts[int(sku_id)] = int(redis_cart[sku_id])
            sku_ids = carts.keys()

            # 遍历购物车中被勾选的商品信息
            for sku_id in sku_ids:
                # 查询SKU信息
                while True:
                    # 查询SKU信息
                    sku = SKU.objects.get(id=sku_id)

                    # 读取原始库存
                    origin_stock = sku.stock
                    origin_sales = sku.sales

                    # 判断SKU库存
                    sku_count = carts[sku.id]
                    if sku_count > origin_stock:
                        # 事务回滚
                        transaction.savepoint_rollback(save_id)
                        return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})

                    # 模拟延迟
                    # import time
                    # time.sleep(5)

                    # SKU减少库存，增加销量
                    # sku.stock -= sku_count
                    # sku.sales += sku_count
                    # sku.save()

                    # 乐观锁更新库存和销量
                    new_stock = origin_stock - sku_count
                    new_sales = origin_sales + sku_count
                    result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                    # 如果下单失败，但是库存足够时，继续下单，直到下单成功或者库存不足为止
                    if result == 0:
                        continue

                    # 修改SPU销量
                    sku.spu.sales += sku_count
                    sku.spu.save()

                    # 保存订单商品信息 OrderGoods（多）
                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        count=sku_count,
                        price=sku.price,
                    )

                    # 保存商品订单中总价和总数量
                    order.total_count += sku_count
                    order.total_amount += (sku_count * sku.price)
                    break
            # 添加邮费和保存订单信息
            order.total_amount += order.freight
            order.save()
        except Exception as e:
            logger.error(e)
            transaction.savepoint_rollback(save_id)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})
        # 提交订单成功，显式的提交一次事务
        transaction.savepoint_commit(save_id)
        # 清除购物车中已结算的商品
        pl = redis_conn.pipeline()
        pl.hdel('carts_%s' % user.id, *selected)
        pl.srem('selected_%s' % user.id, *selected)
        pl.execute()

        # 响应提交订单结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})



class OrderSettlementView(LoginRequiredMixin,View):
    def get(self, request):
        """提供订单结算页面"""
        '''获取登录用户'''
        user = request.user
        '''查询用户没有被删除的地址'''
        try:
            addresses = Address.objects.filter(user = user,is_deleted = False)
        except Exception as e:
            '''没有地址可以点击编辑地址'''
            addresses = None
        '''查询redis购物车中被勾选的商品'''
        redis_conn = get_redis_connection('carts')
        '''购物车内的所有商品'''
        redis_cart =  redis_conn.hgetall('carts_%s'%user.id)
        '''被勾选的商品'''
        cart_selected =  redis_conn.smembers('selected_%s'%user.id )
        cart = {}
        for sku_id in cart_selected:
            cart[int(sku_id)] = int(redis_cart[sku_id])
        '''获取被勾选的商品的skuid'''
        skus = SKU.objects.filter(id__in = cart.keys())
        total_count = 0
        total_amount = Decimal(0.00)
        for sku in skus:
            sku.count = cart[sku.id]
            sku.amount = sku.count*sku.price
            total_count +=sku.count
            total_amount += sku.amount
        freight = Decimal(10.00)
        '''构造上下文'''
        context = {
            'skus':skus,
            'addresses':addresses,
            'total_count':total_count,
            'total_amount':total_amount,
            'freight':freight,#运费
            'total_payment':total_amount+freight,#实付款
        }
        return render(request, 'place_order.html',context)

class OrderSuccessView(LoginRequiredMixin, View):
    """提交订单成功"""

    def get(self, request):
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id':order_id,
            'payment_amount':payment_amount,
            'pay_method':pay_method
        }
        return render(request, 'order_success.html', context)
